export interface Plugin {
  id: string
  name: string
  version: string
  description: string
  author: string
  enabled: boolean
  activate: (context: PluginContext) => void
  deactivate: () => void
  commands?: PluginCommand[]
  settings?: PluginSetting[]
}

export interface PluginCommand {
  id: string
  title: string
  description?: string
  icon?: string
  shortcut?: string
  handler: (context: PluginContext) => void
}

export interface PluginSetting {
  key: string
  title: string
  description?: string
  type: 'string' | 'number' | 'boolean' | 'select'
  default: any
  options?: { label: string; value: any }[]
}

export interface PluginContext {
  editor: any
  fileService: any
  aiService: any
  settingsService: any
  registerCommand: (command: PluginCommand) => void
  unregisterCommand: (commandId: string) => void
  showNotification: (message: string, type?: 'info' | 'success' | 'warning' | 'error') => void
  addMenuItem: (menu: PluginMenuItem) => void
  removeMenuItem: (menuId: string) => void
}

export interface PluginMenuItem {
  id: string
  label: string
  submenu?: PluginMenuItem[]
  click?: () => void
  type?: 'separator' | 'checkbox' | 'radio'
  checked?: boolean
  accelerator?: string
}

class PluginManager {
  private plugins: Map<string, Plugin> = new Map()
  private context: PluginContext
  private eventEmitter: EventTarget = new EventTarget()

  constructor(context: PluginContext) {
    this.context = context
  }

  /**
   * Register a new plugin
   */
  registerPlugin(plugin: Plugin): void {
    if (this.plugins.has(plugin.id)) {
      throw new Error(`Plugin ${plugin.id} is already registered`)
    }

    this.plugins.set(plugin.id, plugin)

    if (plugin.enabled) {
      this.activatePlugin(plugin.id)
    }

    console.log(`Plugin registered: ${plugin.name} (${plugin.id})`)
  }

  /**
   * Unregister a plugin
   */
  unregisterPlugin(pluginId: string): void {
    const plugin = this.plugins.get(pluginId)
    if (!plugin) {
      throw new Error(`Plugin ${pluginId} is not registered`)
    }

    if (plugin.enabled) {
      this.deactivatePlugin(pluginId)
    }

    this.plugins.delete(pluginId)
    console.log(`Plugin unregistered: ${plugin.name} (${pluginId})`)
  }

  /**
   * Activate a plugin
   */
  activatePlugin(pluginId: string): void {
    const plugin = this.plugins.get(pluginId)
    if (!plugin) {
      throw new Error(`Plugin ${pluginId} is not registered`)
    }

    if (plugin.enabled) {
      console.log(`Plugin ${pluginId} is already active`)
      return
    }

    try {
      plugin.activate(this.context)
      plugin.enabled = true

      // Register plugin commands
      if (plugin.commands) {
        plugin.commands.forEach(command => {
          this.context.registerCommand(command)
        })
      }

      this.emit('plugin:activated', { pluginId, plugin })
      console.log(`Plugin activated: ${plugin.name} (${pluginId})`)
    } catch (error) {
      console.error(`Failed to activate plugin ${pluginId}:`, error)
      throw error
    }
  }

  /**
   * Deactivate a plugin
   */
  deactivatePlugin(pluginId: string): void {
    const plugin = this.plugins.get(pluginId)
    if (!plugin) {
      throw new Error(`Plugin ${pluginId} is not registered`)
    }

    if (!plugin.enabled) {
      console.log(`Plugin ${pluginId} is already inactive`)
      return
    }

    try {
      // Unregister plugin commands
      if (plugin.commands) {
        plugin.commands.forEach(command => {
          this.context.unregisterCommand(command.id)
        })
      }

      plugin.deactivate()
      plugin.enabled = false

      this.emit('plugin:deactivated', { pluginId, plugin })
      console.log(`Plugin deactivated: ${plugin.name} (${pluginId})`)
    } catch (error) {
      console.error(`Failed to deactivate plugin ${pluginId}:`, error)
      throw error
    }
  }

  /**
   * Get all registered plugins
   */
  getPlugins(): Plugin[] {
    return Array.from(this.plugins.values())
  }

  /**
   * Get a plugin by ID
   */
  getPlugin(pluginId: string): Plugin | undefined {
    return this.plugins.get(pluginId)
  }

  /**
   * Get enabled plugins
   */
  getEnabledPlugins(): Plugin[] {
    return this.getPlugins().filter(plugin => plugin.enabled)
  }

  /**
   * Enable/disable a plugin
   */
  setPluginEnabled(pluginId: string, enabled: boolean): void {
    const plugin = this.plugins.get(pluginId)
    if (!plugin) {
      throw new Error(`Plugin ${pluginId} is not registered`)
    }

    if (plugin.enabled !== enabled) {
      if (enabled) {
        this.activatePlugin(pluginId)
      } else {
        this.deactivatePlugin(pluginId)
      }
    }
  }

  /**
   * Get plugin commands
   */
  getPluginCommands(): PluginCommand[] {
    const commands: PluginCommand[] = []
    this.getEnabledPlugins().forEach(plugin => {
      if (plugin.commands) {
        commands.push(...plugin.commands)
      }
    })
    return commands
  }

  /**
   * Execute a plugin command
   */
  executeCommand(commandId: string): void {
    const command = this.getPluginCommands().find(cmd => cmd.id === commandId)
    if (!command) {
      throw new Error(`Command ${commandId} not found`)
    }

    try {
      command.handler(this.context)
      this.emit('command:executed', { commandId, command })
    } catch (error) {
      console.error(`Failed to execute command ${commandId}:`, error)
      throw error
    }
  }

  /**
   * Load plugin settings
   */
  loadPluginSettings(pluginId: string): Record<string, any> {
    const plugin = this.plugins.get(pluginId)
    if (!plugin || !plugin.settings) {
      return {}
    }

    const settings: Record<string, any> = {}
    plugin.settings.forEach(setting => {
      const savedValue = localStorage.getItem(`plugin.${pluginId}.${setting.key}`)
      settings[setting.key] = savedValue !== null ? JSON.parse(savedValue) : setting.default
    })

    return settings
  }

  /**
   * Save plugin settings
   */
  savePluginSettings(pluginId: string, settings: Record<string, any>): void {
    const plugin = this.plugins.get(pluginId)
    if (!plugin || !plugin.settings) {
      return
    }

    plugin.settings.forEach(setting => {
      if (settings.hasOwnProperty(setting.key)) {
        localStorage.setItem(`plugin.${pluginId}.${setting.key}`, JSON.stringify(settings[setting.key]))
      }
    })

    this.emit('plugin:settings-changed', { pluginId, settings })
  }

  /**
   * Install plugin from file
   */
  async installPluginFromFile(file: File): Promise<void> {
    try {
      const code = await file.text()
      // In a real implementation, you would:
      // 1. Validate the plugin code
      // 2. Create a sandboxed environment
      // 3. Execute the code to get the plugin object
      // 4. Register the plugin
      console.log('Plugin installation from file not yet implemented')
    } catch (error) {
      console.error('Failed to install plugin from file:', error)
      throw error
    }
  }

  /**
   * Export plugin configuration
   */
  exportConfiguration(): string {
    const config = {
      plugins: this.getPlugins().map(plugin => ({
        id: plugin.id,
        enabled: plugin.enabled,
        settings: this.loadPluginSettings(plugin.id)
      }))
    }
    return JSON.stringify(config, null, 2)
  }

  /**
   * Import plugin configuration
   */
  importConfiguration(configJson: string): void {
    try {
      const config = JSON.parse(configJson)

      config.plugins.forEach((pluginConfig: any) => {
        const plugin = this.plugins.get(pluginConfig.id)
        if (plugin) {
          this.setPluginEnabled(pluginConfig.id, pluginConfig.enabled)
          if (pluginConfig.settings) {
            this.savePluginSettings(pluginConfig.id, pluginConfig.settings)
          }
        }
      })

      this.emit('configuration:imported', { config })
    } catch (error) {
      console.error('Failed to import plugin configuration:', error)
      throw error
    }
  }

  /**
   * Event handling
   */
  on(event: string, callback: EventListener): void {
    this.eventEmitter.addEventListener(event, callback)
  }

  off(event: string, callback: EventListener): void {
    this.eventEmitter.removeEventListener(event, callback)
  }

  private emit(event: string, data: any): void {
    this.eventEmitter.dispatchEvent(new CustomEvent(event, { detail: data }))
  }

  /**
   * Cleanup
   */
  dispose(): void {
    // Deactivate all active plugins
    this.getEnabledPlugins().forEach(plugin => {
      this.deactivatePlugin(plugin.id)
    })

    // Clear all plugins
    this.plugins.clear()
    console.log('Plugin manager disposed')
  }
}

export default PluginManager